package room

import (
	"errors"
	"server/common"

	"github.com/jiyeyuran/mediasoup-go/v2"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
)

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) checkPrepareRoomReqData(data common.SFUPrepareRoomReqData) error {
	// Check if room ID is provided
	if data.RoomId == "" {
		return errors.New("room_id is required in prepare room request")
	}

	// Check if user ID is provided
	if data.UserId == "" {
		return errors.New("user_id is required in prepare room request")
	}

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) sendPrepareRoomSuccessResponse(rid string, connId string, roomId string,
	userId string, caps *mediasoup.RtpCapabilities) {
	resMsg := common.Message{
		Cmd: common.SFU_PREPARE_ROOM_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: 0,
			Msg:  "success",
			Data: common.SFUPrepareRoomResData{
				RoomId:  roomId,
				UserId:  userId,
				RtpCaps: caps,
			},
		},
	}
	s.dispatcher.Dispatch(resMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) sendPrepareRoomErrorResponse(rid string, code int, msg string, roomId string,
	userId string, connId string) {
	resMsg := common.Message{
		Cmd: common.SFU_PREPARE_ROOM_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: code,
			Msg:  msg,
			Data: common.SFUPrepareRoomResData{
				RoomId:  roomId,
				UserId:  userId,
				RtpCaps: nil, // No capabilities if there's an error
			},
		},
	}
	s.dispatcher.Dispatch(resMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) handlePrepareRoomReq(msg common.Message, from common.ServiceInfo,
	connId string) error {
	LOG().WithFields(logrus.Fields{
		"msg":    common.ToJson(msg),
		"from":   from,
		"connId": connId,
	}).Info("Handling Prepare Room Request")

	var data common.SFUPrepareRoomReqData
	if err := mapstructure.Decode(msg.Data, &data); err != nil {
		LOG(msg.Rid).WithError(err).Error("Failed to decode prepare room request data")
		s.sendPrepareRoomErrorResponse(msg.Rid, 1, "failed to decode request data", "", "", connId)
		return nil
	}

	// Validate the request data
	if err := s.checkPrepareRoomReqData(data); err != nil {
		LOG(msg.Rid).WithError(err).Error("Prepare room request data validation failed")
		s.sendPrepareRoomErrorResponse(msg.Rid, 1, err.Error(), data.RoomId, data.UserId, connId)
		return nil
	}

	// Check if roomId exists, if it does, return the existing room, otherwise create a new room
	room := s.roomMgr.GetRoom(data.RoomId)
	if room == nil {
		var err error
		room, err = s.roomMgr.CreateRoom(msg.Rid, data.RoomId, data.UserId)
		if err != nil {
			s.sendPrepareRoomErrorResponse(msg.Rid, 1, "failed to create room: "+err.Error(),
				data.RoomId, data.UserId, connId)
			return nil
		}
		if room == nil {
			s.sendPrepareRoomErrorResponse(msg.Rid, 1, "failed to create room, room is nil",
				data.RoomId, data.UserId, connId)
			return nil
		}
	}

	s.sendPrepareRoomSuccessResponse(msg.Rid, connId, data.RoomId, data.UserId, &room.Router.RtpCaps)

	return nil
}
